/*
 *
 * 名称：历法
 * 功能：通过rili.cfg文件，计算公历和农历的转换，时间运算
 * 作者：清河张
 * 时间：2025.05.11
 *
 */
#include "xzqm.h"
#include "lifa.h"
#include <QString>
#include <QFile>
#include <cstdio>

/*
 *
    甲	乙	丙	丁	戊	己	庚	辛	壬	癸|
==================================================
    子	丑	寅	卯	辰	巳	午	未	申	酉|	戌	亥

    戌	亥	子	丑	寅	卯	辰	巳	午	未|	申	酉

    申	酉	戌	亥	子	丑	寅	卯	辰	巳|	午	未

    午	未	申	酉	戌	亥	子	丑	寅	卯|	辰	巳

    辰	巳	午	未	申	酉	戌	亥	子	丑|	寅	卯

    寅	卯	辰	巳	午	未	申	酉	戌	亥|	子	丑

*/

const char *stripinvalid(const char * begin)
{
    while(*begin)
    {
        if(*begin == '\t' || *begin == ' ' ||
            *begin == '\r' || *begin == '\n')
            ++begin;
        else
            break;
    }
    return begin;
}

LFLOADER::LFLOADER()
{

}

bool LFLOADER::loadcfg(const char *file)
{
    QFile qfile(file);

    if(qfile.open(QIODevice::ReadOnly))
    {
        _db = qfile.readAll().toStdString();
        qfile.close();
        return true;
    }
    return false;
}

QDate LFLOADER::nl0togl(const QDate& date)
{
    const char* begin;
    int y = 0, m, d, n, x;

    begin = strstr(_db.c_str(), "[yinli]");
    while(*begin)
    {
        n = 0;
        std::sscanf(begin, "%04d,%d,%d,y1,%04dn",&y, &m, &d, &n);
        begin = strchr(begin, '\n') + 1;
        if(n == date.year()+1) break;//当前行意义，先换行再退出
    }

    while(*begin)
    {
        x = 0;
        std::sscanf(begin, "%04d,%d,%d,y%d,",&y, &m, &d, &x);
        begin = strchr(begin, '\n') + 1;
        if(x == date.month())
        {
            return QDate(y,m,d).addDays(date.day() - 1);
        }
    }

    return QDate();
}

QDate LFLOADER::gltonl0(const QDate &date)
{
    const char* begin;
    const char* end;
    int nl0year = 0, nl0month = 0, nl0date = 0;//农历阴历年月日
    int y = 0, n, m, d, x, cnt0, cnt1;
    cnt0 = date.year() * 10000 + date.month() * 100 + date.day();

    begin = strstr(_db.c_str(), "[yinli]");
    end = strstr(_db.c_str(), "[yinliend]");

    while(*begin)
    {
        y = 0;
        std::sscanf(begin, "%04d,",&y);
        if(y == date.year()) break;
        begin = strchr(begin, '\n') + 1;
    }

    while(*begin)
    {
        y = m = d = x = 0;
        std::sscanf(begin, "%04d,%d,%d,y%d,",&y, &m, &d, &x);
        cnt1 = y * 10000 + m * 100 + d;
        if(cnt1 <= cnt0)
        {
            nl0month = x;
            nl0date = QDate(y,m,d).daysTo(date) + 1;
            nl0year = y - 1;
            break;
        }
        begin = strchr(begin, '\n') + 1;
    }

    while(*begin)
    {
        x = 0;
        std::sscanf(begin, "%04d,%d,%d,y%d,%04dn",&y,&m,&d,&x,&n);
        begin = strchr(begin, '\n') + 1;
        if(x == 1)
        {
            nl0year = n;
            break;
        }
        if(begin >= end)
        {
            break;
        }
    }

    return {nl0year, nl0month, nl0date};
}

QDateTime LFLOADER::jqtogl(JIE24 & jq)
{
    const char* begin;
    const char* end;
    int year;
    int y, m, d, h, f, s, order = 0;
    QDateTime def;

    if(jq.invalid())
        return def;

    jq.zhouchax(0, year, order);

    begin = strstr(_db.c_str(), "[yangli]");
    end = strstr(_db.c_str(), "[yangliend]");

    while(*begin)
    {
        y = 0;
        std::sscanf(begin, "%04d-", &y);
        begin = strchr(begin, '\n') + 1;
        if(y == year) break;
        if(begin >= end) goto goback;
    }

    while(*begin)
    {
        y = m = d = h = f = s = 0;
        std::sscanf(begin, "%04d-%02d-%d/%02d:%02d:%02d",
                    &y, &m, &d, &h, &f, &s);

        QDateTime dt(QDate(y,m,d),QTime(h,f,s));

        if(dt.isValid()) --order;
        if( order <= 0 ) return dt.addSecs(jq.yu());
        begin = strchr(begin, '\n') + 1;
        if(begin >= end) goto goback;
    }

goback:
    return def;
}

JIE24 LFLOADER::gltojq(const QDateTime &dateTime)
{
    int seconds;
    const char* begin;
    const char* end;
    JIE24 jq;
    QDateTime last(QDate(1900,1,1),QTime(0,0,0));
    int y, m, d, h, f, s, order = 0, last_year;

    begin = strstr(_db.c_str(), "[yangli]");
    end = strstr(_db.c_str(), "[yangliend]");

    while(*begin)
    {
        y = 0;
        std::sscanf(begin, "%04d-", &y);
        begin = strchr(begin, '\n') + 1;
        if(y >= dateTime.date().year() - 1) break;
        if(begin >= end) goto goback;
    }

    last_year = y;

    while(*begin)
    {
        while(!isdigit(*begin))
        {
            ++begin;
        }

        y = m = d = h = f = s = 0;
        std::sscanf(begin, "%04d-%02d-%d/%02d:%02d:%02d",
                    &y, &m, &d, &h, &f, &s);

        QDateTime dt(QDate(y,m,d),QTime(h,f,s));

        if(dt > dateTime)
        {
            seconds = last.secsTo(dateTime);
            jq = JIE24(last_year * 24 + order, seconds);
            break;
        }else{
            last = dt;
            ++order;
        }
        begin = strchr(begin, '\n') + 1;
        if(begin >= end) goto goback;
    }
goback:
    return jq;
}

LFLOADER LIFA::_lfloader;

bool LIFA::init(const char *rlfile)
{
    return _lfloader.loadcfg(rlfile);
}

LIFA::LIFA()
{

}

LIFA LIFA::fromgl(const QDateTime &dateTime)
{
    LIFA lf;
    lf._gl = dateTime.date();
    lf._tm = dateTime.time();
    lf._nl = _lfloader.gltonl0(lf._gl);
    lf._jq = _lfloader.gltojq(dateTime);

    lf.tobazi();
    return lf;
}

LIFA LIFA::fromgl(const QDate &date)
{
    return fromgl(QDateTime(date, QTime(0,0,0)));
}

LIFA LIFA::addDays(int days)
{
    return fromgl(QDateTime(_gl.addDays(days), _tm));
}

LIFA LIFA::addSecs(int secs)
{
    QDateTime dt(_gl, _tm);
    return fromgl(dt.addSecs(secs));
}

QDateTime LIFA::dateTime() const
{
    return QDateTime(_gl, _tm);
}

const BAZI& LIFA::bazi() const
{
    return _bz;
}

const BAZI &LIFA::tobazi()
{
    _bz._n = GANZHI::gz60(nian360());
    _bz._y = GANZHI::gz60(syue360());
    _bz._r = GANZHI::gz60(ri360());
    _bz._s = GANZHI::gz60(hour360());
    return _bz;
}

const char *LIFA::jieqiname() const
{
    return JIEQI(_jq.jie()).name();
}

JIE24 LIFA::jieqi() const
{
    return _jq;
}

QDate LIFA::gl() const
{
    return _gl;
}

QTime LIFA::tm() const
{
    return _tm;
}

QDate LIFA::nl() const
{
    return _nl;
}

const char *LIFA::nlzf(int zhu)
{
    int n,y,r,s,k, x1,x2, len = 0;
    const char* str0;
    const char* str1;

    if ( zhu & NIAN )
    {
        n = _nl.year();
        len += std::snprintf(_buf + len, sizeof(_buf) - len, "%s%s%s%s 年 ",
                      SHUZI(n / 1000).name(), SHUZI((n % 1000) / 100).name(),
                      SHUZI((n % 100) / 10).name(), SHUZI(n % 10).name());
    }

    if ( zhu & YUE )
    {
        y = _nl.month();
        str0 = STRARR {"","正","二","三","四","五","六","七","八","九","十","冬","腊"} [y];
        len += std::snprintf(_buf + len, sizeof(_buf) - len, "%s 月 ", str0);
    }

    if ( zhu & RI )
    {
        r = _nl.day();

        if ( r <= 10 )
        {
            len += std::snprintf(_buf + len, sizeof(_buf) - len, "初%s 日 ",
                                 SHUZI(r).name());
        }
        else
        {
            x1 = r / 10;
            x2 = r % 10;

            if(1 == x1) str0 = "十";
            else if(2 == x1) str0 = "廿";
            else if(3 == x1) str0 = "卅";
            else str0 = "";

            str1 = x2 > 0 ? SHUZI( x2 ).name() : "";
            len += std::snprintf(_buf + len, sizeof(_buf) - len, "%s%s 日 ",
                                 str0, str1 );
        }
    }

    s = _tm.hour();

    if ( zhu & SHI )
    {
        len += std::snprintf(_buf + len, sizeof(_buf) - len, "%s 时 ",
                             ZHI12::JIE24(s).name() );
    }

    if ( zhu & KE )
    {
        k = _tm.minute() / 15;
        len += std::snprintf(_buf + len, sizeof(_buf) - len, "%s 刻 ",
                             SHUZI(k + ( ( s + 1 ) % 2 ) * 4).name() );
    }
    return _buf;
}



















QDateTime LIFA::jq2datetime(JIE24 jq)
{
    return _lfloader.jqtogl(jq);
}

int LIFA::nian360() const
{
    return XUNHUAN (_nl.year() - 184, 360 );
}

int LIFA::sui360() const
{
    return XUNHUAN (_jq.zhou() - 184, 360 );
}

int LIFA::syue360() const
{
    int jn;
    jn = _jq.jiejuliz(1983, JIEQI_T::DAXUE, 360);//甲子月大雪，到今的节气数
    return jn / 2;
}

qint64 LIFA::suimiao() const
{
    JIE24 jq = _jq.xiangqian(JIEQI_T::DONGZHI);
    QDateTime dz = LIFA::jq2datetime( jq );
    QDateTime now(_gl, _tm);
    return dz.secsTo(now);
}

qreal LIFA::jiefen() const
{
    JIE24 jq1 = _jq;
    JIE24 jq2 = _jq+1;
    jq1.yuclear();
    jq2.yuclear();
    QDateTime dt1 = LIFA::jq2datetime( jq1 );
    QDateTime dt2 = LIFA::jq2datetime( jq2 );
    return qreal(_jq.yu()) / qreal(dt1.secsTo(dt2)) + _jq.jie();
}

int LIFA::ri360() const
{
    int d30;
    d30 = QDate (1901,4,16).daysTo(_gl) % 360;
    return XUNHUAN ( d30, 360 );
}

int LIFA::hour360() const
{
    return ( _tm.hour() + 1 ) / 2  + ( ri360() % 5 ) * 12;
}

//0-8 => 一至九运
int LIFA::dayun() const
{
    int sui = _jq.zhou();
    int dy = XUNHUAN (sui - 64, 180 )  / 20;
    return dy;
}

